PE文件是在 windows系統下的可執行文件,他是微軟在 UNIX 的 COFF 格式為基礎製作而成的。而PE文件是指32位元的可執行文件,也稱為 PE32。但是64位元則稱為 PE+ 或 PE32+ ,不可稱為 PE64。
在介紹 PE 格式前,我們要知道一份程式是甚麼由程式碼變成 PE 文件。我們都學過程序語言分成高階語言、組合語言、指令碼等等的,當一份高階語言要執行時,就會透過一系列步驟變成指令碼,再經過指令週期後就能達成我們的任務。

( 會作梗圖了 \OwO/ )
這是一個會寫 hello world 的視窗。
int main()
{
MessageBoxA(0,"hello world","This is title",0);
return 0;
}
這個程序會生出一個寫 hello world 的視窗。
然後 IDE 會根據 calling convention (呼叫慣例) 來生成一段組合語言 :
push 0
push "This is title" //push 到 stack
push "hello world"
push 0
call MassageBoxA
xor eax,eax
ret
太好了,我們把他轉成機器碼前做幾件事來封裝他 :
.rdata ( 用來只能讀取的空間 )title -> 6 byte 放到 .rdata + 0
hello world -> 12 byte 放到 .rdata + 6

MassageBoxA 這東西處理器看不懂在哪裡,所以把它使用的資料位置放入 .idata ( Import Address Table)有些 IDE 會把這放到
.rdata,沒有唯一標準 ( 像是 Visual Studio )
.text
然後幾點要注意的 :
PE model ,所以掛載的 process 都依 PE 格式封裝image base ( 跟 virtual address 很像 ),指向該 model 內容image base 通常是 0x400000然後把這些轉換成機器碼,有興趣可以看白算盤跟MIPS指令集來算算看。
https://inst.eecs.berkeley.edu/~cs61c/resources/MIPS_Green_Sheet.pdf
注意 Little / Big endian :

然後把它組譯成 COFF 格式,就是組譯器生產的封裝檔案。
執行 g++ -c main.cpp 生成 main.o ( 他就是COFF格式 )
用 PEview 看它的結構

然後透過 linker 為這個 COFF 進行連結,就變成 EXE程式 了
我們來看看 linking loader 中會用到的步驟 :
Binding ( 決定 Process 起始位置 )。若是在 linker loader 時做 Binding 產生出 obj 的稱為 "relocatable object file"
linker 把必要資料依 PE格式 寫入 OptionalHeader
詳細可以閱讀文件 : https://docs.microsoft.com/zh-tw/windows/win32/debug/pe-format
向 OS 要求起始位置
依 Complier 交辦 linking 修正資訊做出 linking 修正
Relocation 修正
等等步驟。
太棒了,你現在有了一份 EXE 檔案了 \OwO/
當你運行這個 EXE 時,就會由靜態檔案變成 process
那運行時發生了甚麼呢?
比如說我在 cmd.exe 輸入 msgbox.exe,會發生以下步驟 :
父程序 cmd.exe 發出 system call 請求子程序
到 kernel mode 。OS 生成 Thread 給子程序,並在 userland 紀錄 PEB ( Process environment block ) 跟 TEB ( Thread environment block )。
到 user mode 。然後對 Thread 初始化,把 PE 裝到 memory 還有 PE model 修正。
application loader 修正完後把 EIP 送到 Entry point ,開始程序。
這邊看起來很麻煩,不過好像其實平常用不太到,希望未來多看幾次就可以能熟能生巧。